// This file include the classes used to implement the IPSpyPort
#ifndef _LINUX_OS_
#include "..\StdAfx.h"
#include <stdio.h>
#include <conio.h>
#include <winsock2.h>
#include <WS2TCPIP.H>
#else
#include <stdio.h>
#include <termios.h>
#include <linux/if_ether.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <linux/if.h>

#endif

#include "DAPSystem.h"
#include "DAPSpyPort.h"

#ifndef _LINUX_OS_
unsigned long GetLocalIP()
{
    char szLocalIP[20] = {0};
    char szHostName[128+1] = "\0";
    hostent *phe;
    int i;
    if( gethostname(szHostName, 128 ) == 0 ) {
        // Get host adresses
        phe = gethostbyname(szHostName);
        for( i = 0; phe != NULL && phe->h_addr_list[i]!= NULL; i++ )
        {
            sprintf(szLocalIP, "%d.%d.%d.%d", 
                (UINT)((UCHAR*)phe->h_addr_list[i])[0],
                (UINT)((UCHAR*)phe->h_addr_list[i])[1],
                (UINT)((UCHAR*)phe->h_addr_list[i])[2], 
                (UINT)((UCHAR*)phe->h_addr_list[i])[3]);
        }
    }
    else
        return 0;
	
    return inet_addr(szLocalIP);
}
#endif
// Define the IP Header
class CIPHeader
{
public:
	unsigned char  m_nVersion:4;	// Version of IP
	unsigned char  m_nIHL:4;		// Internet header length
	unsigned char  m_nTypeOfService;// Type of service
	unsigned short m_nTotalLength;  // Total length of frame
	unsigned short m_nIdent;		// 16 bits
	unsigned short m_nFlags:3;		// Flags
	unsigned short m_nFragmentOffset:13; // 13 bits fragment offset
	unsigned char  m_nTimeToLive;   //8????? TTL
	unsigned char  m_nProtocal; //8??? (TCP, UDP ???)
	unsigned short m_nChecksum;    // header check sum
	unsigned int   sourceIP; //32??IP??
	unsigned int   destIP; //32???IP??
// Operation
public:
	int GetIPHeaderLen()
	{
		return m_nIHL*4;
	};
	bool FormIPHeader(unsigned char *pByte){
		unsigned char byValue=*pByte++;
		m_nVersion=(byValue & 0xF0)>>4;
		m_nIHL=(byValue & 0x0F);
		m_nTypeOfService=*pByte++;
		m_nTotalLength=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nIdent=pByte[0]<<8 | pByte[1];
		pByte+=2;
		byValue=*pByte++;
		m_nFlags=(byValue & 0xE0)>>5;
		m_nFragmentOffset =(byValue & 0x1F)<<8 | pByte[0];
		pByte++;
		m_nTimeToLive=*pByte++;
		m_nProtocal=*pByte++;
		m_nChecksum=pByte[0]<<8 | pByte[1];
		pByte+=2;
		memcpy(&sourceIP, pByte,4);
		pByte+=4;
		memcpy(&destIP, pByte,4);
		pByte+=4;
		return true;
	}
};

class CTCPHeader
{
public:
	unsigned short m_nDPort; // Destination port
	unsigned short m_nSPort; // Source port
	unsigned long  m_nSeqenceNo;	 // Sequence no
	unsigned long  m_nAckNo;    // ack no
	unsigned short m_nWindow;		 // 16 bit window
	unsigned short m_nHeaderLength:4; // Data offset
	unsigned short m_nReserved:6;  // Data offset
	unsigned short m_nControlBits:6; // Data offset
	unsigned short m_nCheckSum;			 // 16 check sum
	unsigned short m_nUrgentPointer;			 // 16 bits urgent pointer
public:
	int GetHeaderLength()
	{
		return m_nHeaderLength*4;
	}
	bool FormTCPHeader(unsigned char *pByte)
	{
		m_nDPort=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nSPort=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nSeqenceNo=pByte[0]<<24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3];
		pByte+=4;
		m_nAckNo=pByte[0]<<24 | pByte[1] << 16 | pByte[2] << 8 | pByte[3];
		pByte+=4;
		m_nHeaderLength=(pByte[0] & 0xF0)>>4;
		m_nReserved =((pByte[0] & 0x0F0) << 2) | ((pByte[1] & 0xC0) >>6);
		m_nControlBits=(pByte[1] & 0x3F) >>2;
		pByte+=2;
		m_nWindow=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nCheckSum=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nUrgentPointer=pByte[0]<<8 | pByte[1];
		pByte+=2;

		return true;
	}
};
class CUDPHeader{
public:
	unsigned short	m_nSourcePort;
    unsigned short	m_nDestPort;
    unsigned short	m_nTotalLen;
    unsigned short	m_nCheckSum;
public:
	int GetHeaderLen(){
		return 8;
	};
	int GetDataLen(){
		return m_nTotalLen-8;
	};
	bool FormUDPHeader(unsigned char *pByte){
		m_nSourcePort=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nDestPort=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nTotalLen=pByte[0]<<8 | pByte[1];
		pByte+=2;
		m_nCheckSum=pByte[0]<<8 | pByte[1];
		pByte+=2;
		return true;
	};
};

#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
//Implement the thread of the spy port
#ifdef _LINUX_OS_
bool CTCPPortSpyWorker::InitInstance()
#else
BOOL CTCPPortSpyWorker::InitInstance()
#endif
{
	return true;
}
#ifdef _LINUX_OS_

int CTCPPortSpyWorker::ExitInstance()
{
    CWinThread::onDelete();
    return 1;
}
#else
int CTCPPortSpyWorker::ExitInstance()
{
	return CWinThread::ExitInstance();
}
#endif
/////////////////////////////////////////////////////////////////////////////
// CClientSocket message handlers
//
void CTCPPortSpyWorker::Close()
{
#ifndef _LINUX_OS_
	m_bClose=true;
	SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
	DWORD dwitCode;
	while(GetExitCodeThread(m_hThread, &dwitCode) && dwitCode==STILL_ACTIVE){
		m_bClose=true;
		ResumeThread();
//		WaitForSingleObject(nullEvent, 20);
	}
#else
	m_bClose=true;
//	m_evtSendWait.SetEvent();
    WaitForSingleObject(true);// cancel the thread
#endif
}

#ifdef _LINUX_OS_
void CTCPPortSpyWorker::Run()
#else
int CTCPPortSpyWorker::Run()
#endif
{
    CEvent nullEvent;
#ifdef _LINUX_OS_
    m_hSoc = socket(AF_INET, SOCK_PACKET, htons(0x800));
    struct ifreq ifr;
    strcpy(ifr.ifr_name, "eth0");
    if(ioctl(m_hSoc, SIOCGIFFLAGS, &ifr)==-1) {
       printf("error");
    }
    ifr.ifr_flags |=IFF_PROMISC;
    if(ioctl(m_hSoc, SIOCSIFFLAGS, &ifr)==-1){
        printf("error");
    }
#else
    m_hSoc = INVALID_SOCKET;
    m_hSoc = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
    SOCKADDR_IN addr_in;
	int flag = 1;
	flag = setsockopt(m_hSoc, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag));
	
    addr_in.sin_family = AF_INET;
    addr_in.sin_port  = INADDR_ANY;
    addr_in.sin_addr.S_un.S_addr = GetLocalIP();
    int nRetCode = bind(m_hSoc, (struct sockaddr*)&addr_in, sizeof(addr_in));
    if (SOCKET_ERROR == nRetCode)
    {
        printf("BIND Error!%d\n", WSAGetLastError());
        return -1;
    }
	// dwValue?????????1????0???
	DWORD dwValue = 1;
	// ?? SOCK_RAW ?SIO_RCVALL????????IP????SIO_RCVALL
	// ????? #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
	flag = ioctlsocket(m_hSoc, SIO_RCVALL, &dwValue);
#endif
    unsigned char pBuffer[1024];
	while (!m_bClose){
#ifdef _LINUX_OS_
		int nRe = recvfrom(m_hSoc, (char*) pBuffer, 1024, 0, NULL, NULL);
#else
		int nRe = recv(m_hSoc, (char*) pBuffer, 1024, 0);
#endif
		if(nRe>0){
			CIPHeader ipHeader;
			ipHeader.FormIPHeader(pBuffer);
			CDAPString szSourceIP, szDestIP;
			szSourceIP=inet_ntoa(*(in_addr*)&ipHeader.sourceIP);
			szDestIP=inet_ntoa(*(in_addr*)&ipHeader.destIP);
			if(ipHeader.m_nProtocal==0x06){   //for TCP
				CTCPHeader tcpHeader;
				tcpHeader.FormTCPHeader(pBuffer+ipHeader.GetIPHeaderLen());
				UINT nDestPortNo=tcpHeader.m_nDPort;
				UINT nSourcePortNo=tcpHeader.m_nSPort;
				int nDataOffset=ipHeader.GetIPHeaderLen()+tcpHeader.GetHeaderLength();
#ifndef _LINUX_OS_
/*				CDAPString szMsg;
				szMsg.Format("Source IP:%s, Port:%d, Dest IP: %s,Port:%d\n",(const char *)szSourceIP,nSourcePortNo,(const char*)szDestIP,nDestPortNo);
				TRACE0(szMsg);
				TRACE2("Length:%d,Data Offset:%d\n",nRe, nDataOffset);*/
#endif
				if(nRe-nDataOffset>0)
					m_pSpyPort->AddReceiveTCPData(pBuffer+nDataOffset, nRe-nDataOffset, (const char*)szSourceIP, (const char*)szDestIP,nSourcePortNo,nDestPortNo);
            }
            else if(ipHeader.m_nProtocal==0x11){  //for UDP
    			CUDPHeader udpHeader;
				udpHeader.FormUDPHeader(pBuffer+ipHeader.GetIPHeaderLen());
				int nDataOffset=ipHeader.GetIPHeaderLen()+udpHeader.GetHeaderLen();
#ifndef _LINUX_OS_
//				TRACE2("Source Port:%d, Dest Port:%d\n",udpHeader.m_nSourcePort,udpHeader.m_nDestPort);
//				TRACE1("Data Offset:%d\n",nDataOffset);
#endif
				if(nRe-nDataOffset>0)
					m_pSpyPort->AddReceiveUDPData(pBuffer+nDataOffset, nRe-nDataOffset, (const char*)szSourceIP, (const char*)szDestIP,udpHeader.m_nSourcePort,udpHeader.m_nDestPort);
            }
#ifdef _LINUX_OS_            
            nullEvent.WaitForSingleObject(5);
#else
            WaitForSingleObject(nullEvent, 5);
#endif            
        }
    }
    SocketClosed();
#ifndef _LINUX_OS_
	TRACE0("SPY Thread Exited\n");
	return 1L;
#endif
}
void CTCPPortSpyWorker::SocketClosed()
{
#ifndef _LINUX_OS_
	closesocket(m_hSoc);
#else
	close(m_hSoc);
#endif
}
void CTCPPortSpyWorker::SocketConnected()
{
}
////////////////////////////////////////////////////////////////////////////////////////////////
// Implement CIPSpyPort
//
CIPSpyPort :: CIPSpyPort()
{
	m_pWorkerThread=0;
#ifndef _LINUX_OS_
	AfxSocketInit();
#endif
}
CIPSpyPort :: ~CIPSpyPort()
{
	if(m_pWorkerThread!=0)
		delete m_pWorkerThread;
	while(!m_lstUDPSpyPort.IsEmpty())
		m_lstUDPSpyPort.RemoveHead()->Release();
	while(!m_lstTCPSpyPort.IsEmpty())
		m_lstTCPSpyPort.RemoveHead()->Release();
}

CDAPPortObj *CIPSpyPort :: CreatePort(CDAPPropertyList &lstPort, CDAPString &szError)
{
	CDAPProperty *pProp=lstPort.Get((PTNO)4); //protocol type
	if(pProp==NULL || pProp->m_nValueType!=DAP_UINTEGER_TYPE){
		szError=CDAPString("IP Protocol not selected!");
		return 0;
    }
	bool bTCP=!(pProp->m_uValue.uValue);
	CDAPString szSrvIPAddr, szClientIPAddr;
	unsigned long nSPort=0, nDPort=0;
    pProp=lstPort.Get((PTNO)5);              //Server IP address
	// Server IP Addrress
	if(pProp!=NULL && pProp->m_nValueType==DAP_MSG_TYPE)
	   szSrvIPAddr=pProp->GetValue();
    pProp=lstPort.Get((PTNO)6);              //Client IP address
	// Client IP Addrress
	if(pProp!=NULL && pProp->m_nValueType==DAP_MSG_TYPE)
		szClientIPAddr=pProp->GetValue();
	// SPort
    pProp=lstPort.Get((PTNO)7);              //Client IP address
	if(pProp!=0 && pProp->m_nValueType==DAP_UINTEGER_TYPE)
		nSPort=pProp->m_uValue.uValue;
	// DPort
    pProp=lstPort.Get((PTNO)8);              //Client IP address
	if(pProp!=0 && pProp->m_nValueType==DAP_UINTEGER_TYPE)
		nDPort=pProp->m_uValue.uValue;
	if(bTCP){
		POSITION pos=m_lstTCPSpyPort.GetHeadPosition();
		while(pos){
			CDAPTCPSpyPort *pPort=m_lstTCPSpyPort.GetNext(pos);
			if(pPort->IsSameAs(szSrvIPAddr,nSPort,szClientIPAddr))
				return 0;
		}
		CDAPTCPSpyPort *pPort=new CDAPTCPSpyPort(szSrvIPAddr,nSPort,szClientIPAddr);
		m_lstTCPSpyPort.AddTail(pPort);
		pPort->AddRef();
		return pPort;
	}
	else{
		POSITION pos=m_lstUDPSpyPort.GetHeadPosition();
		while(pos){
			CDAPUDPSpyPort *pPort=m_lstUDPSpyPort.GetNext(pos);
			if(pPort->IsSameAs(nSPort,nDPort,szSrvIPAddr,szClientIPAddr))
				return 0;
		}
		CDAPUDPSpyPort *pPort=new CDAPUDPSpyPort(nSPort,nDPort,szSrvIPAddr,szClientIPAddr);
		m_lstUDPSpyPort.AddTail(pPort);
		pPort->AddRef();
		return pPort;
	}
	return 0;
}
void CIPSpyPort :: AddReceiveTCPData(unsigned char *pBuffer, int nLen, const char* szSAddr, const char* szDAddr,unsigned long dwSPort, unsigned long dwDPort)
{
	CPhyRcvPackage *pRcvPack=new CPhyRcvPackage(pBuffer, nLen, szSAddr, true,szDAddr);
	pRcvPack->AddRef();
	POSITION pos=m_lstTCPSpyPort.GetHeadPosition();
	while(pos){
		CDAPTCPSpyPort *pPort=m_lstTCPSpyPort.GetNext(pos);
		if(pPort->AddFrame(pRcvPack,dwSPort, dwDPort)){
			pRcvPack->Release();
			return;
		}
	}
	pRcvPack->Release();
}
void CIPSpyPort :: AddReceiveUDPData(unsigned char *pBuffer, int nLen, const char* szSAddr, const char* szTAddr,unsigned long dwSPort,unsigned long dwDPort)
{
	CPhyRcvPackage *pRcvPack=new CPhyRcvPackage(pBuffer, nLen, szSAddr, true,szTAddr);
	pRcvPack->AddRef();
	POSITION pos=m_lstUDPSpyPort.GetHeadPosition();
	while(pos){
		CDAPUDPSpyPort *pPort=m_lstUDPSpyPort.GetNext(pos);
		if(pPort->AddFrame(pRcvPack,dwSPort,dwDPort)){
			pRcvPack->Release();
			return;
		}
	}
	pRcvPack->Release();
}
bool CIPSpyPort :: CheckStartPort()
{
	if(!m_lstTCPSpyPort.IsEmpty() || !m_lstUDPSpyPort.IsEmpty()){
		if(m_pWorkerThread==0){
			m_pWorkerThread=new CTCPPortSpyWorker(this);
			if(!m_pWorkerThread->CreateThread()){
				delete m_pWorkerThread;
				return false;
			}
		}
	}
	else if(m_pWorkerThread!=0){
		m_pWorkerThread->Close();
		delete m_pWorkerThread;
		m_pWorkerThread=0;
	}
	return true;
}
bool CIPSpyPort :: CheckStopPort()
{
	if(m_pWorkerThread!=0){
		m_pWorkerThread->Close();
		delete m_pWorkerThread;
		m_pWorkerThread=0;
	}
	return true;
}

// Implement CDAPUDPSpyPort

CDAPUDPSpyPort :: CDAPUDPSpyPort(unsigned long nSVSendPort, unsigned long nSVRcvPort, CDAPString szBroadCastAddr,CDAPString szClientAddr)
{
	m_nSendPort=nSVSendPort;
	m_nRcvPort=nSVRcvPort;
	m_szSvrAddress=szBroadCastAddr;
	m_szClientAddress=szClientAddr;
}
CDAPUDPSpyPort :: ~CDAPUDPSpyPort()
{
}
CDAPString  CDAPUDPSpyPort :: GetPortName()
{
	CDAPString szPortName;
	szPortName.Format("M%s:SP%d:RP%d:C%s",(const char*)m_szSvrAddress,m_nSendPort,m_nRcvPort,(const char*)m_szClientAddress);
	return szPortName;
} 
bool CDAPUDPSpyPort :: AddFrame(CPhyRcvPackage *pPackage, unsigned long nSourcePort, unsigned long nTargetPort)
{
	if(m_nRcvPort==nTargetPort){
		pPackage->m_bRcvFlag=1;
		if(m_szSvrAddress.IsEmpty() || !m_szSvrAddress.CompareNoCase(pPackage->m_szSourceAddr)) 
			ReceivePackage(pPackage);
		return true;
	}
	if(m_nSendPort==nTargetPort){
		pPackage->m_bRcvFlag=0;
		if(m_szClientAddress.IsEmpty() || !m_szClientAddress.CompareNoCase(pPackage->m_szSourceAddr))
		    ReceivePackage(pPackage);
		return true;
	}
	return false;
}
bool CDAPUDPSpyPort :: IsSameAs(unsigned long nSVSendPort, unsigned long nSVRcvPort, CDAPString szBroadCastAddr,CDAPString szClientAddr)
{
	if(m_nRcvPort==nSVRcvPort && (m_szSvrAddress.IsEmpty() || szBroadCastAddr.IsEmpty() || !m_szSvrAddress.CompareNoCase(szBroadCastAddr)))
		return true;
	if(m_nSendPort==nSVSendPort && (m_szClientAddress.IsEmpty() || szClientAddr.IsEmpty() || !m_szClientAddress.CompareNoCase(szClientAddr)))
		return true;
	return false;
}
// Implement CDAPTCPSpyPort
CDAPTCPSpyPort :: CDAPTCPSpyPort(CDAPString szSvrAddr, unsigned long nSVListenPort, CDAPString szClientAddr)
{
	m_szSvrAddress=szSvrAddr;
	m_nLstPort=nSVListenPort;
	m_szClientAddress=szClientAddr;

}
CDAPTCPSpyPort :: ~CDAPTCPSpyPort()
{
}
CDAPString  CDAPTCPSpyPort :: GetPortName()
{
	CDAPString szPortName;
	szPortName.Format("M%s:P%d:C%s",(const char*)m_szSvrAddress,m_nLstPort,(const char*)m_szClientAddress);
	return szPortName;
} 
bool CDAPTCPSpyPort :: AddFrame(CPhyRcvPackage *pPackage, unsigned long uSPort,unsigned long uDPort)
{
	if(uSPort!=m_nLstPort && uDPort!=m_nLstPort)
		return false;
	if(!m_szSvrAddress.IsEmpty() && m_szSvrAddress.CompareNoCase(pPackage->m_szSourceAddr) && m_szSvrAddress.CompareNoCase(pPackage->m_szTargetAddr))
		return false;
	if(!m_szClientAddress.IsEmpty() && m_szClientAddress.CompareNoCase(pPackage->m_szSourceAddr) && m_szClientAddress.CompareNoCase(pPackage->m_szTargetAddr))
		return false;
	if(!m_szSvrAddress.IsEmpty()){
		if((!m_szSvrAddress.CompareNoCase(pPackage->m_szSourceAddr) && (!m_szClientAddress.IsEmpty() && m_szClientAddress.CompareNoCase(pPackage->m_szTargetAddr))) ||
			(!m_szSvrAddress.CompareNoCase(pPackage->m_szTargetAddr) && (!m_szClientAddress.IsEmpty() && m_szClientAddress.CompareNoCase(pPackage->m_szSourceAddr))))
			return false;
		if(!m_szSvrAddress.CompareNoCase(pPackage->m_szSourceAddr))
			pPackage->m_bRcvFlag=1;
		else
			pPackage->m_bRcvFlag=0;
	}
	else if(!m_szClientAddress.IsEmpty()){
		if((!m_szClientAddress.CompareNoCase(pPackage->m_szSourceAddr) && (!m_szSvrAddress.IsEmpty() && m_szSvrAddress.CompareNoCase(pPackage->m_szTargetAddr))) ||
			(!m_szClientAddress.CompareNoCase(pPackage->m_szTargetAddr) && (!m_szSvrAddress.IsEmpty() && m_szSvrAddress.CompareNoCase(pPackage->m_szSourceAddr))))
			return false;
		if(!m_szClientAddress.CompareNoCase(pPackage->m_szSourceAddr))
			pPackage->m_bRcvFlag=0;
		else
			pPackage->m_bRcvFlag=1;
	}
	else{
		if(uSPort==m_nLstPort)
			pPackage->m_bRcvFlag=0;
		else
			pPackage->m_bRcvFlag=1;
	}
	ReceivePackage(pPackage);	
	return true;
}
bool CDAPTCPSpyPort :: IsSameAs(CDAPString szSvrAddr, unsigned long nSVListenPort, CDAPString szClientAddr)
{
	if(nSVListenPort!=m_nLstPort)
		return false;
	if((szSvrAddr.IsEmpty() && szClientAddr.IsEmpty()) ||
		(m_szSvrAddress.IsEmpty() && m_szClientAddress.IsEmpty()))
		return true;
	if(!szSvrAddr.CompareNoCase(szSvrAddr) && !szClientAddr.CompareNoCase(szClientAddr))

		return false;
	return true;
}
